<HTML>
<head>
<title>AngelScript: Documentation: Registering a C++ class</title>
<LINK rel="stylesheet" type="text/css" href="style.css">
</head>


<body>


<p>
<a href="../index.html">index</a>
</p>

<h1>Registering a C++ class</h1>

<p>The are two principal paths to take when registering a new type, either the
type is a reference type that is located in dynamic memory, or the type is a
value type that is located on the stack. Complex types are usually registered
as reference types, while simple types that are meant to be used as primitives
are registered as value types. A reference type support object handles (unless restricted by application), but
cannot be passed by value to application registered functions, a value type
doesn't support handles and can be passed by value to application registered
functions.</p>

<ul>
<li><a href="#basicref">Registering a basic reference type</a>
<li><a href="#gcref">Registering a garbage collected reference type</a>
<li><a href="#noinst">Registering an uninstanciable reference type</a>
<li><a href="#single">Registering a single-reference type</a>
<li><a href="#scoped">Registering a scoped type</a>
<li><a href="#val">Registering a value type</a>
<li><a href="#opbeh">Registering operator behaviours</a>
<li><a href="#objmeth">Registering object methods</a>
<li><a href="#objprop">Registering object properties</a>
</ul>

<a name=basicref>
<h2>Registering a basic reference type</h2>

<p>The basic reference type should be registered with the following behaviours:
asBEHAVE_FACTORY, asBEHAVE_ADDREF, and asBEHAVE_RELEASE. If it is desired that
assignments should be allowed for the type the asBEHAVE_ASSIGNMENT behaviour
must be registered as well. Other behaviours, such as math operators,
comparisons, etc may be registered as needed.</p>

<pre class=border>
<font color=green>// Registering the reference type</font>
r = engine->RegisterObjectType("ref", 0, asOBJ_REF); assert( r >= 0 );
</pre>

<h3>Factory function</h3>

<p>The factory function is the one that AngelScript will use to instanciate
objects of this type when a variable is declared. It is responsible for
allocating and initializing the object memory.</p>

<p>The default factory function doesn't take any parameters and should return
an object handle for the new object. Make sure the object's reference counter
is accounting for the reference being returned by the factory function, so
that the object is properly released when all references to it are removed.</p>

<pre class=border>
CRef::CRef()
{
    <font color=green>// Let the constructor initialize the reference counter to 1</font>
    refCount = 1;
}

CRef *Ref_Factory()
{
    <font color=green>// The class constructor is initializing the reference counter to 1</font>
    return new CRef();
}

<font color=green>// Registering the factory behaviour</font>
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_FACTORY, "ref@ f()", asFUNCTION(Ref_Factory), asCALL_CDECL); assert( r >= 0 );
</pre>

<p>You may also register factory functions that take parameters, which may
then be used when initializing the object.</p>

<p>The factory function must be registered as a global function, but can be
implemented as a static class method, common global function, or a global
function following the generic calling convention.</p>

<h3>Addref and release behaviours</h3>

<pre class=border>
void CRef::Addref()
{
    <font color=green>// Increase the reference counter</font>
    refCount++;
}

void CRef::Release()
{
    <font color=green>// Decrease ref count and delete if it reaches 0</font>
    if( --refCount == 0 )
        delete this;
}

<font color=green>// Registering the addref/release behaviours</font>
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ADDREF, "void f()", asMETHOD(CRef,AddRef), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASE, "void f()", asMETHOD(CRef,Release), asCALL_THISCALL); assert( r >= 0 );
</pre>

<h3>Assignment behaviour</h3>

<pre class=border>
CRef &amp;CRef::operator =(const CRef &amp;other)
{
    <font color=green>// Copy everything from the other class, except the reference counter</font>
}

<font color=green>// Registering the assignment behaviour</font>
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ASSIGNMENT, "ref &amp;f(const &amp;in)", asMETHOD(CRef,operator=), asCALL_THISCALL); assert( r >= 0 );
</pre>

<p>The assignment behaviour can be overloaded with other types if that is
desired, that way the script writer doesn't have to manually convert the
expressions before assigning the values to the type.</p>




<a name=gcref></a>
<h2>Registering a garbage collected reference type</h2>

<p>Reference counting as memory management has a drawback in that it is
difficult to detect circular references when determining dead objects.
AngelScript allows the application to register types with special behaviours
to support the garbage collection for detecting circular references. These
behaviours make the class a bit more complex, but you should only have to
register them for a few types, e.g. generic container classes.</p>

<pre class=border>
<font color=green>// Registering the garbage collected reference type</font>
r = engine->RegisterObjectType("ref", 0, asOBJ_REF | asOBJ_GC); assert( r >= 0 );
</pre>

<p>The difference between the garbage collected and non-garbage collected
types is in the addref and release behaviours, the class constructor, and
the extra support behaviours.</p>

<h3>GC support behaviours</h3>

<p>The GC determines when objects should be destroyed by counting the
references it can follow for each object. If the GC can see all references
that points to an object, it knows that the object is part of a circular
reference. If all the objects involved in that circular reference have no
outside references it means that they should be destroyed.</p>

<p>The process of determining the dead objects uses the first for of the
behaviours below, while the destruction of the objects is done by forcing the
release of the object's references.</p>

<pre class=border>
void CGCRef::SetGCFlag()
{
    <font color=green>// Set the gc flag as the high bit in the reference counter</font>
    refCount |= 0x80000000;
}

bool CGCRef::GetGCFlag()
{
    <font color=green>// Return the gc flag</font>
    return (refCount &amp; 0x80000000) ? true : false;
}

int CGCRef::GetRefCount()
{
    <font color=green>// Return the reference count, without the gc flag</font>
    return (refCount &amp; 0x7FFFFFFF);
}

void CGCRef::EnumReferences()
{
    <font color=green>// Call the engine::GCEnumCallback for all references to other objects held</font>
    engine->GCEnumCallback(myref);
}

void CGCRef::ReleaseAllReferences()
{
    <font color=green>// When we receive this call, we are as good as dead, but
    // the garbage collector will still hold a references to us, so we
    // cannot just delete ourself yet. Just free all references to other
    // objects that we hold</font>
    if( myref )
    {
        myref->Release();
        myref = 0;
    }
}

<font color=green>// Register the GC support behaviours</font>
r = engine->RegisterObjectBehaviour("gc", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CGCRef,SetGCFlag), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("gc", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CGCRef,GetGCFlag), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("gc", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CGCRef,GetRefCount), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("gc", asBEHAVE_ENUMREFS, "void f(int&amp;in)", asMETHOD(CGCRef,EnumReferences), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("gc", asBEHAVE_RELEASEREFS, "void f(int&amp;in)", asMETHOD(CGCRef,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 );
</pre>

<h3>Factory for garbage collection</h3>

<p>Whenever a garbage collected class is created, the garbage collector must
be notified of it's existence. The easiest way of doing that is to have the
factory behaviour, or the class constructor call the
NotifyGarbageCollectorOfNewObject() method on the engine when initializing the
class.</p>

<pre class=border>
CGCRef *GCRef_Factory()
{
    <font color=green>// Create the object and then notify the GC of its existence</font>
    CGCRef *obj = new CGCRef();
    int typeId = engine->GetTypeIdByDecl("gc");
    engine->NotifyGarbageCollectorOfNewObject(obj, typeId);
    return obj;
}
</pre>

<p>You may want to consider caching the typeId, so that it doesn't have to be
looked up through the relatively expensive call to GetTypeIdByDecl every time
an object of this type is created.</p>

<p>Note, if you create objects of this type from the application side, you
must also notify the garbage collector of its existence, so it's a good idea
to make sure all code use the same way of creating objects of this type.</p>

<h3>Addref and release for garbage collection</h3>

<p>For garbage collected objects it is important to make sure the AddRef and
Release behaviours clear the GC flag. Otherwise it is possible that the GC
incorrectly determine that the object should be destroyed.</p>

<pre class=border>
void CGCRef::AddRef()
{
    <font color=green>// Clear the gc flag and increase the reference counter</font>
    refCount = (refCount&amp;0x7FFFFFFF) + 1;
}

void CGCRef::Release()
{
    <font color=green>// Clear the gc flag, decrease ref count and delete if it reaches 0</font>
    refCount &amp;= 0x7FFFFFFF;
    if( --refCount == 0 )
        delete this;
}

<font color=green>// Registering the addref/release behaviours</font>
r = engine->RegisterObjectBehaviour("gc", asBEHAVE_ADDREF, "void f()", asMETHOD(CGCRef,AddRef), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("gc", asBEHAVE_RELEASE, "void f()", asMETHOD(CGCRef,Release), asCALL_THISCALL); assert( r >= 0 );
</pre>






<a name=noinst></a>
<h2>Registering an uninstanciable reference type</h2>

<p>Sometimes it may be useful to register types that cannot be instanciated by
the scripts, yet can be interacted with. You can do this by registering the
type as a normal reference type, but omit the registration of the factory
behaviour. You can later register global properties, or functions that allow the
scripts to access objects created by the application via object handles.</p>

<p>This would be used when the application has a limited number of objects
available and doesn't want to create new ones. For example singletons, or
pooled objects.</p>






<a name=single></a>
<h2>Registering a single-reference type</h2>

<p>A variant of the uninstanciable reference types is the single-reference
type. This is a type that have only 1 reference accessing it, i.e. the script
cannot store any extra references to the object during execution. The script
is forced to use the reference it receives from the application at the moment
the application passes it on to the script.</p>

<p>The reference can be passed to the script through a property, either global
or a class member, or it can be returned from an application registered
function or class method.</p>

<pre class=border>
<font color=green>// Registering the type so that it cannot be instanciated
// by the script, nor allow scripts to store references to the type</font>
r = engine->RegisterObjectType("single", 0, asOBJ_REF | asOBJ_NOHANDLE); assert( r >= 0 );
</pre>

<p>This sort of type is most useful when you want to have complete control over
references to an object, for example so that the application can destroy and
recreate objects of the type without having to worry about potential references
held by scripts. This allows the application to control when a script has access
to an object and it's members.</p>




<a name=scoped></a>
<h2>Registering a scoped type</h2>

<p>Some C++ value types have special requirements for the memory where they
are located, e.g. specific alignment needs, or memory pooling. Since
AngelScript doesn't provide that much control over where and how value types
are allocated, they must be registered as reference types. In this case you'd
register the type as a scoped reference type.</p>

<p>A scoped reference type will have the life time controlled by the scope of
the variable that instanciate it, i.e. as soon as the variable goes out of
scope the instance is destroyed. This means that the type doesn't permit
handles to be taken for the type.</p>

<p>A scoped reference type requires two behaviours to be registered, the
factory and the release behaviour. The addref behaviour is not permitted.</p>

<p>Since no handles can be taken for the object type, there is no need to keep
track of the number of references held to the object. This means that the
release behaviour should simply destroy and deallocate the object as soon as
it's called.</p>

<pre class=border>
scoped *Scoped_Factory()
{
  return new scoped;
}

void Scoped_Release(scoped *s)
{
  if( s ) delete s;
}

<font color=green>// Registering a scoped reference type</font>
r = engine->RegisterObjectType("scoped", 0, asOBJ_REF | asOBJ_SCOPED); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("scoped", asBEHAVE_FACTORY, "scoped @f()", asFUNCTION(Scoped_Factory), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("scoped", asBEHAVE_RELEASE, "void f()", asFUNCTION(Scoped_Release), asCALL_CDECL_OBJLAST); assert( r >= 0 );
</pre>






<a name=val></a>
<h2>Registering a value type</h2>

<p>When registering a value type, the size of the type must be given so that AngelScript knows how much space is needed for it.
If the type doesn't require any special treatment, i.e. doesn't contain any pointers or other resource references that must be
maintained, then the type can be registered with the flag asOBJ_POD. In this case AngelScript doesn't require the default
constructor, assignment behaviour, or destructor as it will be able to automatically handle these cases the same way it handles
built-in primitives.</p>

<p>If the type will be passed to and from the application by value using native calling conventions, it is important to inform
AngelScript of its real type in C++, otherwise AngelScript won't be able to determine exactly how C++ is treating the type in
a parameter or return value. There are a few different flags for this:</p>

<p><table border=0 cellspacing=0 cellpadding=0>
<tr><td>asOBJ_APP_CLASS             &nbsp; </td><td>The C++ type is a class, struct, or union</td></tr>
<tr><td>asOBJ_APP_CLASS_CONSTRUCTOR &nbsp; </td><td>The C++ type has a defined constructor</td></tr>
<tr><td>asOBJ_APP_CLASS_DESTRUCTOR  &nbsp; </td><td>The C++ type has a defined destructor</td></tr>
<tr><td>asOBJ_APP_CLASS_ASSIGNMENT  &nbsp; </td><td>The C++ type has a defined assignment operator</td></tr>
<tr><td>asOBJ_APP_PRIMITIVE         &nbsp; </td><td>The C++ type is a C++ primitive, but not a float or double</td></tr>
<tr><td>asOBJ_APP_FLOAT             &nbsp; </td><td>The C++ type is a float or double</td></tr>
</table></p>


<pre class=border>
<font color=green>// Register a primitive type, that doesn't need any special management of the content</font>
r = engine->RegisterObjectType("pod", sizeof(pod), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); assert( r >= 0 );

<font color=green>// Register a class that must be properly initialized and uninitialized</font>
r = engine->RegisterObjectType("val", sizeof(val), asOBJ_VALUE | asOBJ_APP_CLASS_CDA); assert( r >= 0 );
</pre>

<h3>Constructor and destructor</h3>

<p>If a constructor or destructor is needed they shall be registered the following way:</p>

<pre class=border>
void Constructor(void *memory)
{
  <font color=green>// Initialize the pre-allocated memory by calling the
  // object constructor with the placement-new operator</font>
  new(memory) Object();
}

void Destructor(void *memory)
{
  <font color=green>// Uninitialize the memory by calling the object destructor</font>
  ((Object*)memory)->~Object();
}

<font color=green>// Register the behaviours</font>
r = engine->RegisterObjectBehaviour("val", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Constructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("val", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Destructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
</pre>

<p>The assignment behaviour is registered the same way as for reference types.</p>





<a name=opbeh></a>
<h2>Registering operator behaviours</h2>

<p>You can register operator behaviours for your types as well. By doing this
you'll allow the script to work with the types in expressions, just like the
built-in types.</p>

<p>There two forms of operator behaviours, either object behaviours or global
behaviours. An object behaviour is implemented as a class method, and a global
behaviour is implemented as a global function.</p>

<pre class=border>
<font color=green>// Registering an object behaviour</font>
int &amp;MyClass::operator[] (int index)
{
  return internal_array[index];
}

r = engine->RegisterObjectBehaviour("mytype", asBEHAVE_INDEX, "int &amp;f(int)", asMETHOD(MyClass,operator[]), asCALL_THISCALL); assert( r >= 0 );

<font color=green>// Registering a global behaviour</font>
MyClass operator+(const MyClass &amp;a, const MyClass &amp;b)
{
  MyClass res = a + b;
  return res;
}

r = engine->RegisterGlobalBehaviour(asBEHAVE_ADD, "mytype f(const mytype &amp;in, const mytype &amp;in)", asFUNCTIONPR(operator+, (const MyClass &amp;, const MyClass &amp;), MyClass), asCALL_CDECL); assert( r >= 0 );
</pre>

<p>You can find a complete list of behaviours <a href="ref_behaviours.html">here</a>.<p>

<a name=objmeth></a>
<h2>Registering object methods</h2>

<p>Class methods are registered with the RegisterObjectMethod call.</p>

<pre class=border>
<font color=green>// Register a class method</font>
void MyClass::ClassMethod()
{
  <font color=green>// Do something</font>
}

r = engine->RegisterObjectMethod("mytype", "void ClassMethod()", asMETHOD(MyClass,ClassMethod), asCALL_THISCALL); assert( r >= 0 );
</pre>

<p>It is also possible to register a global function that takes a pointer to
the object as a class method. This can be used to extend the functionality of
a class when accessed via AngelScript, without actually changing the C++
implementation of the class.</p>

<pre class=border>
<font color=green>// Register a global function as an object method</font>
void MyClass_MethodWrapper(MyClass *obj)
{
   <font color=green>// Access the object</font>
   obj->DoSomething();
}

r = engine->RegisterObjectMethod("mytype", "void MethodWrapper()", asFUNCTION(MyClass_MethodWrapper), asCALL_CDECL_OBJLAST); assert( r >= 0 );
</pre>

<a name=objprop></a>
<h2>Registering object properties</h2>

<p>Class member variables can be registered so that they can be directly
accessed by the script without the need for any method calls.</p>

<pre class=border>
struct MyStruct
{
  int a;
};

r = engine->RegisterObjectProperty("mytype", "int a", offsetof(MyStruct,a)); assert( r >= 0 );
</pre>

<p>offsetof() is a macro declared in stddef.h header file.</p>





</body></HTML>
